/* 
 * $Id: DeterministicNode.java 1259 2007-01-09 14:23:47Z tcoupaye $
 *
 * Behavior Protocols extensions for static and runtime checking
 * developed for the Julia implementation of Fractal.
 *
 * Copyright 2004
 *    Distributed Systems Research Group
 *    Department of Software Engineering
 *    Faculty of Mathematics and Physics
 *    Charles University, Prague
 *
 * Copyright (C) 2006
 *    Formal Methods In Software Engineering Group
 *    Institute of Computer Science
 *    Academy of Sciences of the Czech Republic
 *
 * Copyright (C) 2006 France Telecom
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
 *
 * Contact: ft@nenya.ms.mff.cuni.cz
 * Authors: Jan Kofron <kofron@nenya.ms.mff.cuni.cz>
 */

package org.objectweb.fractal.bpc.checker.node;


import java.util.ArrayList;
import java.util.LinkedList;
import java.util.TreeMap;
import java.util.Iterator;
import java.util.Set;
import java.util.TreeSet;

import org.objectweb.fractal.bpc.checker.DFSR.CheckingException;
import org.objectweb.fractal.bpc.checker.state.*;
import org.objectweb.fractal.bpc.checker.utils.AnotatedProtocol;

/**
 * Represented operation of determinization.
 */
public class DeterministicNode extends TreeNode {

    /**
     * Creates a new instance of DeterministicNode
     */
    public DeterministicNode(TreeNode node) {
        super("Det(" + node.protocol + ")");
        this.nodes = new TreeNode[1];
        this.nodes[0] = node;
    }

    /**
     * @see org.objectweb.fractal.bpc.checker.node.TreeNode#getInitial()
     */
    public State getInitial() {
        State[] state = new State[1];
        state[0] = nodes[0].getInitial();

        return new CompositeState(state);
    }

    /**
     * @see org.objectweb.fractal.bpc.checker.node.TreeNode#isAccepting(org.objectweb.fractal.bpc.checker.state.State)
     */
    public boolean isAccepting(State state) {
        CompositeState cstate = (CompositeState) state;

        for (int i = 0; i < cstate.states.length; ++i)
            if (nodes[0].isAccepting(cstate.states[i]))
                return true;

        return false;

    }

    /**
     * This method creates the deterministic transition set form a
     * nedeterministic one. It creates, of course, for each of the possible
     * transitions via the same event a transition to a newly created
     * CompositeState.
     * 
     * @see org.objectweb.fractal.bpc.checker.node.TreeNode#getTransitions(org.objectweb.fractal.bpc.checker.state.State)
     */
    public TransitionPairs getTransitions(State state) throws InvalidParameterException, CheckingException {
        CompositeState cstate = (CompositeState) state;
        TreeMap transmap = new TreeMap();
        LinkedList deps = new LinkedList();

        int nodecnt = cstate.states.length;

        for (int i = 0; i < nodecnt; ++i) {
            TransitionPairs transp = nodes[0].getTransitions(cstate.states[i]);
            TransitionPair[] trans = transp.transitions;
            
            if (transp.deps != null)
                deps.addAll(transp.deps);
            
            for (int j = 0; j < trans.length; ++j) {
                TreeSet states = (TreeSet) transmap.get(new Integer(trans[j].eventIndex));
                if (states != null) {
                    states.add(trans[j].state);
                } else {
                    states = new TreeSet();
                    states.add(trans[j].state);
                    transmap.put(new Integer(trans[j].eventIndex), states);
                }
            }
        }

        TransitionPair[] result = new TransitionPair[transmap.size()];
        Set keys = transmap.keySet();
        Iterator it = keys.iterator();
        int i = 0;

        while (it.hasNext()) {
            Integer eventindex = (Integer) it.next();
            TreeSet states = (TreeSet) transmap.get(eventindex);
            State[] resultstates = new State[states.size()];

            Iterator it2 = states.iterator();
            int l = 0;

            while (it2.hasNext())
                resultstates[l++] = (State) it2.next();

            result[i++] = new TransitionPair(eventindex.intValue(), new CompositeState(resultstates));
        }

        //TODO: debug only!
        /*
        for (i = 0; i < result.length; ++i)
            result[i].state.getSignature();
        */
        
        TransitionPairs restrans = new TransitionPairs(result);
        restrans.deps = deps;
        return restrans;
    }

    /**
     * 
     * @see org.objectweb.fractal.bpc.checker.node.TreeNode#getWeight()
     */
    public long getWeight() {
        if (weight != -1)
            return weight;
        else {
            return weight = nodes[0].getWeight();
        }
    }
    
    /**
     * @return the symbolic name of the treenode denoting its type
     */
    public String[] getTypeName() {
        String[] result = { "Deterministic", "DET" };
        return result;
    }
    
    

    /**
     * @see org.objectweb.fractal.bpc.checker.node.TreeNode#getAnotatedProtocol(org.objectweb.fractal.bpc.checker.state.State)
     */
    public AnotatedProtocol getAnotatedProtocol(State state) {
        CompositeState cstate = (CompositeState) state;
        String result = new String();
        int cnt = cstate != null ? cstate.states.length : 0;
        ArrayList indicesresult = new ArrayList();

        for (int i = 0; i < cnt; ++i) {
            AnotatedProtocol subresult = nodes[0].getAnotatedProtocol(cstate.states[i]);
            
            for (int j = 0; j < subresult.indices.size(); ++j)
                indicesresult.add(new Integer(((Integer)subresult.indices.get(j)).intValue() + result.length()));
            
        }
        
        result = nodes[0].getAnotatedProtocol(null).protocol;
        
        return new AnotatedProtocol(result, indicesresult);
    }
    

    //---------------------------------------------------------------
}
